/*=====================================================================================
   Program Name: vtr02
   This is a program that normalizes binary voter transition rates in a multi-party setting. 
   The algorithm is from Agresti (1990), and matrix subroutines at the bottom is from  
   Nicholas Cox. 
   
Program written by Won-ho Park, University of Michigan
Copyright Won-ho Park, Sept. 2002 
=======================================================================================
  The input arguments are two sets of vote returns (which means not fractions),
  devided by a "|", the first set being from the first election. Thus, the command
  syntax would be 

  VTR party1_election1 party2_election1 ..., SECond(party1_election2 party2_election2...) 
  And other options are: 
  ecol(default==ecol4, 1==ecol1) 
  TOLerance(real value) 
  Format(STATA display format)

========================================================================================*/

program define VTR, rclass byable(recall)
	version 7.0
	syntax varlist(min=2 numeric) [if] [in] , SECond(varlist numeric min=2) [ecol(passthru) TOLerance(passthru) Format(passthru)]
	marksample touse, strok
	tokenize `varlist'
	local election1 "`3'"  
	tokenize `second'
	tempname pops props out nofobs
*	mat drop _all
	local election2 "`3'"
		if ("`election1'" =="")&("`election2'" ==""){
			vtr01 `varlist' if `touse' `in' , second(`second') `ecol' bin(1)
			mat `props'=r(Props)
			mat `pops' =r(Pops)
			sca `nofobs'=r(n)
			return sca n=`nofobs'
			return mat Props `props'
			return mat Pops `pops'
			qui vtr01 `varlist' if `touse' `in' , second(`second') `ecol'
			mat `out' = r(vtrmat)
			return mat Out `out'
			exit
		}
	if ("`ecol'"=="ecol(1)"){
	local type "Logit"
	}
	else{
	local type "Probit"
	}

	tempname vtrmat vtrates n_tot1 n_tot2 tot2 Out colsum vtrmat2 col row final 
	qui vtr01 `varlist' if `touse' `in' , second(`second') `ecol'
	sca `tot2' = r(tot2)
	mat `vtrates' = r(vtrates)
	mat list r(vtrmat), t("Voter Transition Matrix, `type', Crude") `format'
	mat list r(n)     , t("Number of Valid Observations")
	mat `nofobs'=r(n)
	return mat n `nofobs'
	mat list r(rho)   , t("`type' Correlations, Crude Binary")
	* A Subroutine to make both elections' grand sum meet before running "mstdizem".
	mat `n_tot1' = r(sum1)
	mat `n_tot2' = r(sum2)
	mat `n_tot1' = r(tot2)/r(tot1) * `n_tot1'
*	mat list `n_tot1'
	qui mstdizem `vtrates' `n_tot2' `n_tot1' `vtrmat2', `tolerance'	
*		mat list `vtrmat2', t("Voter Transition Matrix, Standardized") `format'

	mat `pops'=`vtrmat2'
	return mat Pops `pops'

	mat `Out' = `vtrmat2'/`tot2'
	mat `props'=`Out'
	return mat Props `props'
	mat `Out' = `Out', `n_tot2'
	mat `n_tot1' = `n_tot1', `tot2'
	mat `Out' = `Out' \ `n_tot1'
	return mat Out `Out'
	mat list return(Out), t("Voter Transition Rates, `type', Standardized, Unconditional") `format'

	sca `row' = rowsof(`vtrmat2')
	sca `col' = colsof(`vtrmat2')
	local r = `row'
	local c = `col'
	mat `colsum' = J(1, colsof(`vtrmat2'), 0)
	mat `final' = J(`r', 1, 0)

	forvalues i = 1/`c'{
		forvalues j = 1/`r'{
		mat `colsum'[1,`i'] = `colsum'[1,`i'] + `vtrmat2'[`j',`i']
		}
		mat `final' = `final',`vtrmat2'[1..`r',`i']/`colsum'[1,`i']
	*			mat list `final'
	}
	
	mat `final' = `final'[1..., 2...]
	mat rownames `final' = `second'
	*		mat list `final'
	mat `final' = `final', `n_tot2'
	mat `final' = `final' \ `n_tot1'
	return mat final `final'
	mat list return(final), t("Voter Transition Rates, `type', Standardized, Conditional") `format'

end

program define mstdizem
*! version 1.0.0 NJC 23 July 1998
    version 5.0
    parse "`*'", parse(" ,")
    if "`4'" == "" {
        di in r "invalid syntax"
        exit 198
    }
    matchk `1'
    local X "`1'"
    matchk `2'
    local rowtot "`2'"
    matchk `3'
    local coltot "`3'"
    local Y "`4'"
    if "`4'" == "" {
        di in r "invalid syntax"
        exit 198
    }
    mac shift 4
    local options "TOLerance(real 1e-3) Format(string)"
    parse "`*'"

    tempname oner onec sumrow sumcol guess pguess Rowtot Coltot r c
    tempname rowtotm coltotm

    qui {
        local nr = rowsof(matrix(`X'))
        local nc = colsof(matrix(`X'))
        mat `oner' = J(1,`nr',1)
        mat `onec' = J(`nc',1,1)
        mat `sumrow' = `oner' * `rowtot'
        mat `sumcol' = `coltot' * `onec'
        local diffsum = abs(`sumrow'[1,1] - `sumcol'[1,1])
        if `diffsum' > `toleran' {
            di in r "totals of rows and columns do not agree"
            exit 198
        }

        mat `guess' = `X'
        mat `rowtotm' = diag(`rowtot')
        mat `coltotm' = diag(`coltot')
        local max .
        local i = 0
        while `max' > `toleran' {
            local i = `i' + 1
            mat `pguess' = `guess'
            mat `Rowtot' = `guess' * `onec'
            mat `Rowtot' = diag(`Rowtot')
            mat `Rowtot' = inv(`Rowtot')
            mat `r' = `rowtotm' * `Rowtot'
            mat `guess' = `r' * `guess'
            mat `Coltot' = `oner' * `guess'
            mat `Coltot' = diag(`Coltot')
            mat `Coltot' = inv(`Coltot')
            mat `c' = `coltotm' * `Coltot'
            mat `guess' = `guess' * `c'
            matmad `pguess' `guess'
            local max = $S_1
        }
    }

    mat `Y' = `guess'
    if "`format'" == "" { local format "%9.2f" }

    mat li `Y', format(`format')

    global S_1 = `max'
    global S_2 = `i'

end


program define matchk
* matrix?
* matchk `1'
*! 1.0.0 NJC 5 July 1998
    version 5.0
    if "`1'" == "" | "`2'" != "" {
        di in r "invalid syntax"
        exit 198
    }
    tempname C
    mat `C' = `1'
end

program def matmad
* maximum absolute difference between matrices
* matmad A B -- for matrices A, B
*! 1.0.0 NJC 5 July 1998
    version 5.0
    if "`1'" == "" | "`2'" == "" | "`3'" != "" {
        di in r "invalid syntax"
        exit 198
    }

    tempname D
    mat `D' = `1' - `2'

    local nr = rowsof(`D')
    local nc = colsof(`D')
    local max = abs(`D'[1,1])
    local i 1
    while `i' <= `nr' {
        local j = 1
        while `j' <= `nc' {
            local max = max(`max',abs(`D'[`i',`j']))
            local j = `j' + 1
        }
        local i = `i' + 1
    }
    global S_1 = `max'
    di $S_1
end





